// ----------------------------------------------------------------------------
// registration_object.h
// ----------------------------------------------------------------------------
/*
 Description:
 グローバルに配置したオブジェクト、関数の登録用クラス. 
 オブジェクトには優先順位を設定できるので、生成順、実行順を制御できる. 
 
 優先順位を明示的にすることで、初期化、終了処理を明確化でき、プログラム 
 のエントリに登録の為の関数を書き込む必要がなくなる.
 
 たとえば、モジュールの初期化等を独立して記述できるようにすることを意図して用意している.
 
 ----------------------------------------------------------------
 使い方. 
 
 1. プログラムの初期化時、終了時に以下のマクロを配置.
 
 main()
 {
 FW_REGISTER_OBJECT_INITIALIZE();
 メインの処理();
 FW_REGISTER_OBJECT_DESTROY();
 }
 
 2. 任意のソースに関数を記述し、その関数をマクロを使って登録する. 
 
 ...
 #include <fw/base/fw_registration_object.h>
 ...
 void foo( FW_OBJECT_OPERATION operation )
 {
   if( operation == FW_REGISTER_ON_INITIALIZE )
   {
     初期化処理...
   }
   else if( operation == FW_REGISTER_ON_DESTROY )
   {
     終了処理...
   }
 }
 FW_REGISTER_FUNCTION( foo, 0 ); // 関数名と任意のプライオリティ値. プライオリティ値は高いほど優先して実行される.
 // 逆に、プライオリティ値が高いほど後で終了処理が呼び出される. (初期化時と逆順).
 
 3. 登録されたオブジェクトを確認したい場合、FW_REGISTER_OBJECT_DUMP マクロを利用する. 
 コンソールに登録された関数名がプライオリティー順で出力される. 
 
 FW_REGISTER_OBJECT_DUMP();
 
 ※静的ライブラリに登録オブジェクトを作成する場合は関数が呼び出されるスコープに
 登録オブジェクトを配置すること.  これはC++の仕様による制約. 
 
 */
#pragma once
#include <fw/base/core/macros.h>
#include <fw/base/core/noncopyable.h>

namespace fw
{
	class RegisteredObjectInterface : private NonCopyable
	{
	public:
		
		enum ObjectOperation
		{
			kObjectOperation_Initialize = 0,	/**< 初期化操作. CallInitialize呼び出し時に設定される.  */
			kObjectOperation_Destroy			/**< 終了時操作. CallDestroy呼び出し時に設定される. */
		}; // enum ObjectOperation 
		
		RegisteredObjectInterface( const char* pName, int priority );
		
		virtual ~RegisteredObjectInterface();
		
	private:
		
		friend class 					Register;
		
		virtual void 					operator()( const ObjectOperation operation ) = 0;
		
		const char* 					GetName() const;
		
		int 							GetPriority() const;
		
		static int 						IsLessPriority( const void* pL, const void* pR );
		
		const char*						m_pName;
		
		int								m_priority;
		
	}; // class RegisteredObjectInterface 
	
	class RegisteredFunction : public RegisteredObjectInterface
	{
	public:
		
		typedef void (*PFnRegisteredFunction)( ObjectOperation operation );
		
		RegisteredFunction( const char*									pName,
						   PFnRegisteredFunction						pFunction,
						   int											priority );
		
	public:
		
		virtual void					operator()( const ObjectOperation operation );
		
		PFnRegisteredFunction			m_pFunction;
		
	}; // class RegisteredFunction 
	
	class Register
	{
	public:
		
		static void 					CallInitialize();
		
		static void 					CallDestroy();
		
		static void						DumpRegisteredObject();
		
	private:
		
		friend class RegisteredObjectInterface;
		
		static void 					RegisterObject		( RegisteredObjectInterface& rObject );
		
		static void 					UnregisterObject	( RegisteredObjectInterface& rObject );
		
		typedef RegisteredObjectInterface*					RegisteredList;
		
		static RegisteredList* 			s_pRegisteredObjects;
		
		static int 						s_registeredObjectsCount;
		
	}; // class Register 
	
} // namespace fw

#define FW_REGISTER_OBJECT( RegisterClass, Name, ... )	static RegisterClass FW_CONCAT( s_oRegisteredObject, Name )( __VA_ARGS__ )

#define FW_REGISTER_FUNCTION( Functor, priority ) \
	FW_REGISTER_OBJECT( ::fw::RegisteredFunction, Functor, __FILE__ "(" FW_STR(__LINE__) "): " FW_STR(Functor), Functor, priority )

#define FW_REGISTER_OBJECT_DUMP()		::fw::Register::DumpRegisteredObject()

#define FW_OBJECT_OPERATION				::fw::RegisteredObjectInterface::ObjectOperation

#define FW_REGISTER_ON_INITIALIZE		::fw::RegisteredObjectInterface::kObjectOperation_Initialize
#define FW_REGISTER_ON_DESTROY			::fw::RegisteredObjectInterface::kObjectOperation_Destroy

// Initialize / Terminate 
#define FW_REGISTER_OBJECT_INITIALIZE()	::fw::Register::CallInitialize()
#define FW_REGISTER_OBJECT_DESTROY()	::fw::Register::CallDestroy()

// Priority
#define FW_REGISTER_OBJECT_PRIO_MEMORY_ALLOCATION	(65535) // これより大きなプライオリティを設定しない. 
#define FW_REGISTER_OBJECT_PRIO_SYSTEM_FLOOR		(32768) // システムはこれよりも大きなプライオリティを設定する. 

